package com.example.threadcode.higherLeverFour.MatMult.v2;

import java.util.ArrayList;
import java.util.List;

import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveAction;

/**
 * 使用Fork/Join框架,将任务划分,并行执行.优化
 */
public class MatMult extends RecursiveAction
{
   private final Matrix a, b, c;
   private final int row;

   /**
    * 这个构造器默认调用MatMult(Matrix a, Matrix b, Matrix c, int row) 构造器
    */
   public MatMult(Matrix a, Matrix b, Matrix c)
   {
      this(a, b, c, -1);
   }

   public MatMult(Matrix a, Matrix b, Matrix c, int row)
   {
      if (a.getCols() != b.getRows())
         throw new IllegalArgumentException("rows/columns mismatch");
      this.a = a;
      this.b = b;
      this.c = c;
      this.row = row;
   }
/**
 * 这是RecursiveAction的方法,在这里重写用来实现自定义的任务分解.
 *    等于是把任何划分为a.getRows() (a的行)个子任务.
 *    虽然compute()通常用于递归的将任务细分为子任务,但這里为了简洁选择稍微不同的方式处理乘法任务.
 *    当row=-1,这方法创建MatMult的集合,然后将这集合传递给RecursiveAction’s Collection<T> invokeAll(Collection<T> tasks)
 *    方法(这个方法的任务类型是继承ForkJoinTask的).这方法并行执行集合中所有的任务.
 *    然后，它等待invokeAll()方法返回(它也连接到所有这些任务)，
 *    当布尔isDone()方法(也继承自ForkJoinTask)为每个任务返回true时，就会发生这种情况。
 *    当invokeAll()被调用,每个任务的compute()方法会执行然后检测row的值(其他值不是-1).就会去执行
 *    multiplyRowByColumn(a, b, c, row);方法
  */
   @Override
   public void compute()
   {
      if (row == -1)
      {
         List<MatMult> tasks = new ArrayList<>();
         for (int row = 0; row < a.getRows(); row++)
            tasks.add(new MatMult(a, b, c, row));
         invokeAll(tasks);
      }
      else
         multiplyRowByColumn(a, b, c, row);
   }

   public static void multiplyRowByColumn(Matrix a, Matrix b, Matrix c, 
                                          int row)
   {
      for (int j = 0; j < b.getCols(); j++)
         for (int k = 0; k < a.getCols(); k++)
            c.setValue(row, j, c.getValue(row, j) + 
                       a.getValue(row, k) * b.getValue(k, j));
   }

   public static void dump(Matrix m)
   {
      for (int i = 0; i < m.getRows(); i++)
      {
         for (int j = 0; j < m.getCols(); j++)
            System.out.print(m.getValue(i, j) + " ");
         System.out.println();
      }
      System.out.println();
   }

   /**
    * 主方法创建a,b矩阵之后创建C矩阵并且实例化ForkJoinPool,在这池中在实例化MatMult,并将
    * a,b,c矩阵作为参数传递进MatMult实例,接着调用ForkJoinPool实例的invoke(ForkJoinTask<T> task)方法
    * 去启动运行初始化那些任务.這个方法不会返回,直到任务初始化并他的所有子任务都完成才会往下执行.
    *
    */
   public static void main(String[] args)
   {
      Matrix a = new Matrix(2, 3);
      a.setValue(0, 0, 1); // | 1 2 3 |
      a.setValue(0, 1, 2); // | 4 5 6 |
      a.setValue(0, 2, 3);
      a.setValue(1, 0, 4);
      a.setValue(1, 1, 5);
      a.setValue(1, 2, 6);
//      dump(a);
      Matrix b = new Matrix(3, 2);
      b.setValue(0, 0, 7); // | 7 1 |
      b.setValue(1, 0, 8); // | 8 2 |
      b.setValue(2, 0, 9); // | 9 3 |
      b.setValue(0, 1, 1);
      b.setValue(1, 1, 2);
      b.setValue(2, 1, 3);
//      dump(b);
      Matrix c = new Matrix(2, 2);
      ForkJoinPool pool = new ForkJoinPool();
      pool.invoke(new MatMult(a, b, c));
      dump(c);
   }
}